package pub.fjf.http;

import java.util.ArrayList;
import java.util.HashMap;

import pub.fjf.tools.Json;
import pub.fjf.tools.PathClassLoader;
import pub.fjf.tools.PathCompiler;
import pub.fjf.tools.StringTools;

public class ApplicationServer extends HttpRequestFilter{
	private String applicationMapPath;
	private String servletMapPath;
	private HashMap<String,Application> applicationMap;
	private HashMap<String,HttpServlet> servletMap;
	private PathClassLoader applicationClassLoader=null;
	private PathClassLoader servletClassLoader=null;
	public ApplicationServer(){
		
	}

	public String getApplicationMapPath() {
		return applicationMapPath;
	}

	public void setApplicationMapPath(String applicationMapPath) {
		this.applicationMapPath = applicationMapPath;
	}

	public String getServletMapPath() {
		return servletMapPath;
	}

	public void setServletMapPath(String servletMapPath) {
		this.servletMapPath = servletMapPath;
	}
	public HashMap<String, Application> getApplicationMap() {
		return applicationMap;
	}

	public void setApplicationMap(HashMap<String, Application> applicationMap) {
		this.applicationMap = applicationMap;
	}

	public void addApplication(String id,Application application) {
		this.applicationMap.put(id, application);
	}
	public Application getApplication(String id) {
		return this.applicationMap.get(id);
	}
	public void removeApplication(String id) {
		this.applicationMap.remove(id);
	}

	public HashMap<String, HttpServlet> getServletMap() {
		return servletMap;
	}

	public void setServletMap(HashMap<String, HttpServlet> servletMap) {
		this.servletMap = servletMap;
	}

	public void addServlet(String url,HttpServlet servlet) {
		this.servletMap.put(url, servlet);
	}
	
	public void removeServlet(String url) {
		this.servletMap.remove(url);
	}
	
	@Override
	public boolean handleHttpRequest(String url, HttpRequest httpRequest, HttpResponse httpResponse) {
		// TODO Auto-generated method stub
		boolean result=false;
		HttpServlet servlet=this.servletMap.get(url);
		if(servlet!=null) {
			if(httpRequest.getMethod().equals("GET")) {
				servlet.doGet(httpRequest, httpResponse);
			}else if(httpRequest.getMethod().equals("POST")) {
				servlet.doPost(httpRequest, httpResponse);
			}
			result=true;
		}
		return result;
	}
	public void config(Json jsonVar) {
		String path=this.getWebProject().getRootPath();
		if(path.length()>0&&path.charAt(path.length()-1)!='/') {
			path=path+'/';
		}
		String applicationMapPath=jsonVar.getJsonVar("this.applicationMapPath").getValueString();
		if(!applicationMapPath.equals("undefine")) {
			this.setApplicationMapPath(applicationMapPath);
			applicationMapPath=path+applicationMapPath;
			String jsonText=StringTools.readAsPath(applicationMapPath);
			if(jsonText!=null) {
				Json json=new Json(jsonText);
				try {
					this.configApplicationMap(json);
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
		String servletMapPath=jsonVar.getJsonVar("this.servletMapPath").getValueString();
		if(!servletMapPath.equals("undefine")) {
			this.setServletMapPath(servletMapPath);
			servletMapPath=path+servletMapPath;
			String jsonText=StringTools.readAsPath(servletMapPath);
			if(jsonText!=null) {
				Json json=new Json(jsonText);
				try {
					this.configServletMap(json);
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}
	public void configApplicationMap(Json jsonVar) throws Exception {
		this.applicationClassLoader=new PathClassLoader(this.getWebProject().getRootPath(),this.getWebProject().getProjectClassLoader());
		HashMap<String,Application> newApplicationMap=new HashMap<String,Application>();
		PathCompiler pathCompiler=new PathCompiler(HttpServer.classPath+";"+this.getWebProject().getClassPath(),this.getWebProject().getRootPath());
		ArrayList<Json> appList=jsonVar.getElements();
		for(int i=0;i<appList.size();i++) {
			Json app=appList.get(i);
			if(app.getTypeCode()==Json.TYPE_OBJECT) {
				String id=app.getMember("id").getValueString();
				String className=app.getMember("className").getValueString();
				String content=app.getMember("content").getValueString();
				String applicationName=app.getMember("applicationName").getValueString();
				Class<?> C=null;
				try {
					C=Class.forName(className, true, this.getWebProject().getProjectClassLoader());
				} catch (ClassNotFoundException e) {}
				if(C==null) {
					String javaPath;
					if(content!=null && content.length()>0) {
						javaPath=content+'/'+applicationName+".java";
					}else {
						javaPath=applicationName+".java";
					}
					pathCompiler.compile(javaPath);
					String classPath;
					if(content!=null && content.length()>0) {
						classPath=content+'/'+applicationName+".class";
					}else {
						classPath=applicationName+".class";
					}
					C=this.applicationClassLoader.readClass(classPath);
				}
				if(C!=null) {
					try {
						Application application=(Application)(C.newInstance());
						application.setApplicationServer(this);
						application.config();
						newApplicationMap.put(id, application);
					} catch (InstantiationException | IllegalAccessException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}
		}
		this.applicationMap=newApplicationMap;
	}
	public void configServletMap(Json jsonVar) throws Exception {
		this.servletClassLoader=new PathClassLoader(this.getWebProject().getRootPath(),this.applicationClassLoader);
		HashMap<String,HttpServlet> newServletMap=new HashMap<String,HttpServlet>();
		PathCompiler pathCompiler=new PathCompiler(HttpServer.classPath+";"+this.getWebProject().getClassPath(),this.getWebProject().getRootPath());
		ArrayList<Json> serList=jsonVar.getElements();
		for(int i=0;i<serList.size();i++) {
			Json ser=serList.get(i);
			if(ser.getTypeCode()==Json.TYPE_OBJECT) {
				String urlMapping=ser.getMember("urlMapping").getValueString();
				String className=ser.getMember("className").getValueString();
				String content=ser.getMember("content").getValueString();
				String servletName=ser.getMember("servletName").getValueString();
				Class<?> C=null;
				try {
					C=Class.forName(className, true, this.getWebProject().getProjectClassLoader());
				} catch (ClassNotFoundException e) {}
				if(C==null) {
					String javaPath;
					if(content!=null && content.length()>0) {
						javaPath=content+'/'+servletName+".java";
					}else {
						javaPath=servletName+".java";
					}
					pathCompiler.compile(javaPath);
					String classPath;
					if(content!=null && content.length()>0) {
						classPath=content+'/'+servletName+".class";
					}else {
						classPath=servletName+".class";
					}
					C=this.servletClassLoader.readClass(classPath);
				}
				if(C!=null) {
					try {
						HttpServlet servlet=(HttpServlet)(C.newInstance());
						servlet.setApplicationServer(this);
						newServletMap.put(urlMapping, servlet);
					} catch (InstantiationException | IllegalAccessException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}
		}
		this.servletMap=newServletMap;
	}
}
